#include "longinstance2.h"
#include "freefuncs.h"
#include <assert.h>

void LongInstance2::addPhase(const Neighborhood2* newNB, int newLabel)
{
	this->neighborhood.push_back((Neighborhood*)newNB);//////////here is the problem: It is pushed back as a Neighborhood not a Neighborhood2 (Neighbor's copy constructor is called not Neighborhood2).
	this->updateTotalHash();
	this->label = newLabel;
}

void LongInstance2::addPhase(const ImageMatrix& image, int row, int col, int nbRadius, int newLabel)
{
	Neighborhood* toBeAdded = new Neighborhood2(image, row, col, nbRadius);
	this->neighborhood.push_back(toBeAdded);
	this->label = newLabel;
	this->updateTotalHash();

}

int LongInstance2::getFeatureSize() const
{
	if (this->neighborhood.size() == 0)
		return 0;
	Neighborhood2* nb0 = (Neighborhood2*) this->neighborhood[0];
	return (int)this->neighborhood.size() * nb0->getSize();
	//return (int)this->neighborhood.size() * intPosPow((2*NRADIUS+1),2);
}

LongInstance2::LongInstance2(const LongInstance2& other)
{
	this->label = other.label;
	this->totalHash = other.totalHash;
	this->conflictNum = other.conflictNum;
	for (int i = 0; i != (int)other.coordinate.size(); i++)
		this->coordinate.push_back(other.coordinate[i]);
	Neighborhood2 *newNB, *otherNB;
	for (int i = 0; i != (int)other.neighborhood.size(); i++)
	//for (vector<Neighborhood*>::const_iterator i = other.neighborhood.begin(); i != other.neighborhood.end(); ++i)
	{
		otherNB = (Neighborhood2*) other.neighborhood[i]; //get a hold of the pointer to other's NB
		//otherNB->setRadius((int) sqrt((double)other.getNeighborhoodSize()) - 2); //APPARENTLY we don't need this, the radius is already set.
		
		//otherNB = (Neighborhood2*) i;
		newNB = new Neighborhood2(*otherNB); //duplicate other NB
		this->neighborhood.push_back(newNB); //add it to itself's vector
	}
}

LongInstance2::LongInstance2 ()
{
	this->label = -1;
	this->totalHash = -1;
	this->conflictNum = 0;
}

LongInstance2::~LongInstance2 ()
{
	//vector<Neighborhood*>::iterator i = this->neighborhood.begin();
	//for (; i != neighborhood.end(); ++i)
	//	delete *i;
	Neighborhood2* nb2ptr;
	for (int i = 0; i < (int) neighborhood.size(); ++i)
	{
		nb2ptr = (Neighborhood2*) this->neighborhood[i];
		delete nb2ptr;
	}
	this->neighborhood.clear();
	//this->coordinate.clear();
	//this->label = 0;
	//this->totalHash = 0;
	//this->conflictNum = 0;

}

bool LongInstance2::hasSameFeature (const LongInstance2& other) const
{
	if (this->neighborhood.size() != other.neighborhood.size())
		return false;
	Neighborhood2 *myNBP, *otherNBP;
	for (int i = 0; i < (int) this->neighborhood.size(); ++i)
	{
		myNBP = (Neighborhood2*) this->neighborhood[i];
		otherNBP = (Neighborhood2*) other.neighborhood[i];
		if (!myNBP->isEqual(*otherNBP))
			return false;
	}
	return true;
}

bool LongInstance2::hasSameFeature (const vector<Neighborhood*>& nb) const
{
	if (this->neighborhood.size() != nb.size())
		return false;
	Neighborhood2 *myNBP, *otherNBP;
	for (int i = 0; i < (int) this->neighborhood.size(); ++i)
	{
		myNBP = (Neighborhood2*) this->neighborhood[i];
		otherNBP = (Neighborhood2*) nb[i];
		if (!myNBP->isEqual(*otherNBP))
			return false;
	}
	return true;
}

LongInstance2::LongInstance2 (string* feature, int strNum, int label, int radius)
{
	for (int i = 0; i < strNum; ++i)
	{
		Neighborhood2* toBeAdded = new Neighborhood2(feature[i], radius);
		this->neighborhood.push_back(toBeAdded);
	}
	this->label = label;
}

int LongInstance2::getNeighborhoodSize() const
{
	assert (this->neighborhood.size() > 0 && "There is no neighborhood to return its size.");
	Neighborhood2* nb2ptr = (Neighborhood2*) neighborhood[0];
	return nb2ptr->getSize();
}

int LongInstance2::getFeature (int neighborhoodIndex, int featureIndex) const
{
	assert(neighborhoodIndex < (int) this->neighborhood.size() && featureIndex < getNeighborhoodSize());
	Neighborhood2* nb2ptr = (Neighborhood2*) this->neighborhood[neighborhoodIndex];
	return nb2ptr->getFeature(featureIndex);
}

int LongInstance2::getFeature (int longFeatureIndex) const
{
	int nbSize = this->getNeighborhoodSize();
	assert(longFeatureIndex < (int) this->neighborhood.size() * nbSize &&
		"assertion failed: trying to read an out of range feature");
	int neighborhoodIndex = longFeatureIndex / nbSize;
	int featureIndex = longFeatureIndex % nbSize;
	Neighborhood2* nb2ptr = (Neighborhood2*) this->neighborhood[neighborhoodIndex];
	return nb2ptr->getFeature(featureIndex);
}